#pragma once
#include "base/RefCounted.h"
#include "base/Time.h"

namespace xBase
{
    class IxDispatcher
    {
    public:
        IxDispatcher() {}
        virtual ~IxDispatcher() {}

        virtual BOOL Dispatch(const MSG& msg) = 0;
    };

    class IxDelegate
    {
    public:
        IxDelegate() {}
        virtual ~IxDelegate() {}

        virtual BOOL DoWork() = 0;

        virtual BOOL DoDelayedWork(xBase::CTime * pNextDelayedWorkTime) = 0;

        virtual BOOL DoIdleWork() = 0;
    };

    class CxMessageFilter
    {
    public:
        virtual BOOL PreTranslateMessage(MSG* pMsg) = 0;
    };

    class CxMessagePump : public xBase::CRefCounted<CxMessagePump>
    {
    public:
        CxMessagePump();
        virtual ~CxMessagePump();

    public:
        VOID RunWithDispatcher(IxDelegate* pDelegate, IxDispatcher* pDispatcher);

        virtual VOID Run(IxDelegate* pDelegate)
        {
            RunWithDispatcher(pDelegate, NULL);
        }

        virtual VOID Quit();

        virtual VOID ScheduleWork() = 0;

        virtual VOID ScheduleDelayedWork(const xBase::CTime& oDelayedWorkTime) = 0;

    protected:
        struct CxRunState
        {
            IxDelegate*     m_pDelegate;
            IxDispatcher*   m_pDispatcher;

            BOOL            m_bShouldQuit;

            INT             m_nRunDepth;
        };

        virtual VOID DoRunLoop() = 0;

        INT GetCurrentDelay() const;

    protected:
        xBase::CTime    m_oDelayedWorkTime;
        LONG            m_nHaveWork;
        CxRunState*     m_pState;
    };
}